#!/usr/bin/env python3
# coding: utf-8

import argparse
import logging
import shutil
import subprocess
import os
import signal
import tempfile

from apps.libs.process.ssh import kill_ansible_ssh_process

ANSIBLE_RUNNER_COMMAND = "ansible-runner"

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
APPS_DIR = os.path.join(PROJECT_DIR, 'apps')
TEMP_DIR = os.path.join(PROJECT_DIR, "tmp")

DEFAULT_SHARE_DIR = os.path.join(PROJECT_DIR, "data", "share")
DEFAULT_ANSIBLE_MODULES_DIR = os.path.join(APPS_DIR, "libs", "ansible", "modules")
DEFAULT_CONTROL_SOCK_PATH = os.path.join(DEFAULT_SHARE_DIR, "control.sock")

DEFAULT_TCP_LISTEN_ADDRESS = "0.0.0.0:7521"

logger = logging.getLogger(__name__)

os.chdir(APPS_DIR)


class ReceptorService:
    def __init__(self):
        self.pid_file = os.path.join(TEMP_DIR, "receptor.pid")
        self.receptor_command = [
            'receptor',
            '--local-only',
            '--node', 'id=primary',
            '--log-level', 'level=Error',
            '--control-service',
            'service=control',
            'tcplisten={}'.format(DEFAULT_TCP_LISTEN_ADDRESS),
            '--work-command',
            'worktype={}'.format(ANSIBLE_RUNNER_COMMAND),
            'command={}'.format(ANSIBLE_RUNNER_COMMAND),
            'params=worker',
            'allowruntimeparams=true',
            '--work-command',
            'worktype={}'.format("kill"),
            'command={}'.format("python"),
            "params={} kill".format(os.path.join(PROJECT_DIR, "receptor")),
            'allowruntimeparams=true'
        ]


    @staticmethod
    def before_start():
        os.makedirs(os.path.join(DEFAULT_SHARE_DIR), exist_ok=True)
        status_dir = os.path.join(tempfile.gettempdir(), "receptor")
        if os.path.exists(status_dir):
            shutil.rmtree(status_dir)

    def start(self):
        self.before_start()
        if os.path.exists(self.pid_file):
            with open(self.pid_file, 'r') as f:
                pid_str = f.read()
            try:
                pid = int(pid_str)
                os.kill(pid, 0)
                print("\n- Receptor service is already running.")
                return
            except ProcessLookupError:
                print("\n- PID file exists but process does not, starting Receptor...")
            except ValueError:
                print("\n- PID file is corrupted, starting Receptor...")
                os.remove(self.pid_file)

        os.environ.update({'LOCAL_CONNECTION_ENABLED': '1'})
        os.environ.setdefault('ANSIBLE_LIBRARY', DEFAULT_ANSIBLE_MODULES_DIR)
        os.environ.update({'PYTHONPATH': APPS_DIR})
        process = subprocess.Popen(self.receptor_command)
        with open(self.pid_file, 'w') as f:
            f.write(str(process.pid))
        print("\n- Receptor service started successfully.")

        def exit_handler(signum, frame):
            process.terminate()
            process.kill()

        signal.signal(signal.SIGINT, exit_handler)
        signal.signal(signal.SIGTERM, exit_handler)
        process.wait()

    def stop(self):
        if not os.path.exists(self.pid_file):
            print("\n- Receptor service is not running.")
            return
        with open(self.pid_file, 'r') as f:
            pid = int(f.read())
        try:
            os.kill(pid, signal.SIGTERM)
            os.remove(self.pid_file)
            print("\n- Receptor service stopped successfully.")
        except ProcessLookupError:
            print("\n- Failed to stop Receptor service: Process does not exist.")
            os.remove(self.pid_file)

    def restart(self):
        self.stop()
        self.start()

    def status(self):
        if os.path.exists(self.pid_file):
            with open(self.pid_file, 'r') as f:
                pid_str = f.read()
            try:
                pid = int(pid_str)
                os.kill(pid, 0)
                print("\n- Receptor service is running.")
                return
            except ProcessLookupError:
                print("\n- Receptor service is not running.")
        else:
            print("\n- Receptor service is not running.")


def handle_receptor_action(args):
    action = args.action
    srv = ReceptorService()
    if action == "start":
        srv.start()
    elif action == 'stop':
        srv.stop()
    elif action == "restart":
        srv.restart()
    elif action == "status":
        srv.status()
    elif action == "kill":
        kill_progress_tree()


def kill_progress_tree(pid=None):
    if not pid:
        try:
            pid_input = input()
            pid = int(pid_input)
            logger.info("progress {} will be kill".format(pid))
            kill_ansible_ssh_process(pid)
        except Exception as e:
            logger.error(e)
            return


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="""
           Jumpserver receptor service control tools;
           """
    )
    parser.add_argument(
        'action', type=str,
        choices=("start", "stop", "restart", "status", "kill"),
        help="Action to run"
    )

    # parser.add_argument('--pid', type=int, default=42, help='what PID you want to kill')

    args = parser.parse_args()
    handle_receptor_action(args)
